package pzl.media.dsp;

import android.annotation.SuppressLint;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;

public class H264EncodeCameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, android.hardware.Camera.PreviewCallback {
    private TextView tvmsg;

    private SurfaceView surfaceView;
    private SurfaceHolder surfaceHolder;

    private Camera camera;
    private android.hardware.Camera.Parameters parameters;

    /**
     * 限制缓存的camera图像最多帧数
     */
    private static final int MAX_CAMERA_DATA_FRAME = 10;
    /**
     * 缓存camera预览帧图像
     * 存储的单元为camera预览的一帧图像（byte[] YUV颜色数据的数组,没通过编码压缩的原始图像数据，YUV格式的）
     */
    public static ArrayBlockingQueue<byte[]> YUVQueue = new ArrayBlockingQueue<>(MAX_CAMERA_DATA_FRAME);

    int WIDTH = 640;//640
    int HEIGHT = 480;//480
    int framerate = 24;
    int biterate = 8500 * 1000;


    private H264Encoder h264Encoder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_h264_encode_camera);
        tvmsg = findViewById(R.id.tvMediaCodecMsg2);

        if (checkDeviceSupport()) {
            Toast.makeText(this, "设备支持H264编解码器", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(this, "设备不支持", Toast.LENGTH_LONG).show();
        }

        surfaceView = findViewById(R.id.MediaCodecSurf);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
    }


    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
        tvmsg.append("surfaceChanged - " + new Date().toLocaleString() + "\n w = " + width + " , h = " + height);

        //获取camera实例
        camera = null;
        try {
            camera = Camera.open(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //初始化 配置参数 绑定预览显示组件，启动相机
        if (camera != null) {
            try {
                camera.setPreviewCallback(this);
                camera.setDisplayOrientation(90);
                if (parameters == null) {
                    parameters = camera.getParameters();
                }
                parameters = camera.getParameters();
                parameters.setPreviewFormat(ImageFormat.NV21);
                parameters.setPreviewSize(WIDTH, HEIGHT);
                camera.setParameters(parameters);
                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * 启动线程 循环地向MediaCodec输送视频数据，MediaCodec让DSP处理数据，然后从MediaCodec去取编码压缩好的数据，写到本地文件里去
         * camera的预览图像被缓存在YUVQueue里面，视频数据从 YUVQueue缓存队列 里面取
         */
        h264Encoder = new H264Encoder(WIDTH, HEIGHT, framerate, biterate);
        h264Encoder.startEncoderThread();
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        //1.camera停止预览、释放资源  2.停止线程中mediaCodec的本session任务，释放资源
        if (null != camera) {
            camera.setPreviewCallback(null);
            camera.stopPreview();
            camera.release();
            camera = null;
            h264Encoder.stopThread();
        }
    }


    @Override
    public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
        //camera 预览时的一帧图像数据的回调
        cacheCameraFrameData(data, data.length);
    }

    /**
     * 缓存一帧camera图像数据
     *
     * @param frameData
     * @param length
     */
    public void cacheCameraFrameData(byte[] frameData, int length) {
        if (YUVQueue.size() >= MAX_CAMERA_DATA_FRAME) {//限制最大缓存10帧图像，随着camera的预览不断更新（YUVQueue缓存的是最新的10帧预览图像）
            YUVQueue.poll();
        }
        YUVQueue.add(frameData);
    }


    /**
     * 检查设备是否支持 h264
     *
     * @return
     */
    @SuppressLint("NewApi")
    private boolean checkDeviceSupport() {
        if (Build.VERSION.SDK_INT >= 18) {
            for (int j = MediaCodecList.getCodecCount() - 1; j >= 0; j--) {
                MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(j);
                String[] types = codecInfo.getSupportedTypes();
                for (int i = 0; i < types.length; i++) {
                    if (types[i].equalsIgnoreCase("video/avc")) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public void click(View v) {
        switch (v.getId()) {
            case R.id.btnMediaCodecStop:
                h264Encoder.stopThread();

                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        finish();
                    }
                }, 1000);
                break;
        }
    }


}
